
// RTOS Kernel Headers
#include <kernelConfig.h>
#include <timer.h>
#include <task.h>
#include <interrupt.h>
#include <kernelAsm.h>

// NDS Headers
#include <nds.h>

volatile unsigned int systemTick;

struct TIMER_STRUCT timerList;

extern struct TCB *currentTask;

/*
 * Name	 : IncrementTick
 * Description :
 * Parameter : None
 */
void IncrementTick(void)
{
	unsigned int flag;

	systemTick++;
//	printf("tick!! %d\n", systemTick);

//	HwTimerClearInterrupt(TIMER0);
//	IntClearPend(INT_TIMER0);

	TimerExpiredCheck();

	/* fixme */
	if(!currentTask->timeQuantum--)
	{
		currentTask->timeQuantum = CONFIG_SCHED_TIME_QUANTUM;

		TaskDequeue(currentTask);

		TaskEnqueue(currentTask);

//		DoScheduling();

		currentTask = TaskSelect();
	}
}

/*
 * Name	 : InitTick
 * Description :
 * Parameter : None
 */
void InitTick(void)
{
	TIMER0_DATA = TIMER_FREQ_256(1000);
	TIMER0_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_DIV_256;
	irqSet(IRQ_TIMER0, TICK_HANDLER);
	irqEnable(IRQ_TIMER0);
}

/*
 * Name	 : InitTimer
 * Description :
 * Parameter : None
 */
void InitTimer(void)
{
	timerList.next = (struct TIMER_STRUCT*)&timerList;
	timerList.prev = (struct TIMER_STRUCT*)&timerList;
}

/*
 * Name	 : TimerInit
 * Description :
 * Parameter : timer -
 *             timeOut -
 *             handler -
 *             args -
 */
int TimerInit(struct TIMER_STRUCT *timer, unsigned int timeOut, void(*handler)(void *), void *args)
{
	unsigned int flag;

	timer->timeOut = timeOut;
	timer->handler = handler;

//	flag = IntSaveDisableIRQ();

	timer->next = (struct TIMER_STRUCT *)(&timerList);
	timer->prev = (struct TIMER_STRUCT *)(&timerList)->prev;

	timerList.prev->next = timer;
	timerList.prev = timer;

//	IntRestoreIRQ(flag);

	return 0;
}

/*
 * Name	 : TimerExpiredCheck
 * Description :
 * Parameter : None
 */
void TimerExpiredCheck(void)
{
	struct TIMER_STRUCT *timer;

//	printf("%d\n", systemTick);

	timer = (&timerList)->next;

	while(1)
	{
		if(timer == (struct TIMER_STRUCT *)&timerList)
		{
			break;
		}

		if(timer->timeOut <= systemTick)
		{
			timer->prev->next = timer->next;
			timer->next->prev = timer->prev;
			timer->handler(timer->args);
		}

		timer = timer->next;
	}
}
